﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Spectrum
{
    /// <summary>
    /// 国家规范反应谱
    /// </summary>
    public class GBCodeSpectrum: SpectSet
    {
        /// <summary>
        /// 特征周期值
        /// </summary>
        private double ModelTg { set; get; }

        /// <summary>
        /// 地震影响系数最大值
        /// </summary>
        private double ModelAfaMax { set; get; }

        /// <summary>
        /// 6s后是否拉平处理
        /// </summary>
        private bool is6Horizontal { set; get; }

        /// <summary>
        /// 一致衰减规律
        /// 广东省隔震规范
        /// </summary>
        private bool is6SameAs5Tg { set; get; }

        /// <summary>
        /// 下降斜率调整系数
        /// </summary>
        private double Factor1
        {
            get
            {
                var value = 0.02 + (0.05 - this.DampingRatio) / (4 + 32 * this.DampingRatio);
                return value < 0 ? 0 : value;
            }
        }

        /// <summary>
        /// 阻尼调整系数
        /// </summary>
        private double Factor2
        {
            get
            {
                var value = 1 + (0.05 - this.DampingRatio) / (0.08 + 1.6 * this.DampingRatio);
                return value < 0.55 ? 0.55 : value;
            }
        }

        /// <summary>
        /// 衰减指数
        /// </summary>
        private double Gamma
        {
            get
            {
                return 0.9 + (0.05 - this.DampingRatio) / (0.3 + 6 * this.DampingRatio);
            }
        }

        /// <summary>
        /// 根据周期计算影响系数
        /// </summary>
        /// <param name="period"></param>
        /// <returns></returns>
        private double PeriodToAfa(double period)
        {
            //5Tg到6.0规范公式
            Func<double, double> getAfa = subPeriod =>
            {
                return (this.Factor2 * Math.Pow(0.2, this.Gamma) - this.Factor1 * (subPeriod - 5 * this.ModelTg)) * this.ModelAfaMax;
            };
            //周期小于零不存在
            if (period < 0) return -1;
            //0到0.1
            else if (period <= 0.1)
            {
                return (this.Factor2 * this.ModelAfaMax - 0.45 * this.ModelAfaMax) / 0.1 * period + 0.45 * this.ModelAfaMax;
            }
            //0.1到Tg
            else if (period <= this.ModelTg) return this.Factor2 * this.ModelAfaMax;
            //Tg到5Tg
            else if (period <= 5 * this.ModelTg || this.is6SameAs5Tg)
                return Math.Pow(this.ModelTg / period, this.Gamma) * this.Factor2 * this.ModelAfaMax;
            //6s内
            else if (period <= 6) return getAfa(period);
            //6s外
            else return this.is6Horizontal ? getAfa(6) : getAfa(period);
        }

        /// <summary>
        /// 正则化
        /// </summary>
        /// <returns></returns>
        public override void Regularization()
        {
            //反应谱折减
            this.SpectrumAmplitude((float)this.GetReductionFactor());
        }

        /// <summary>
        /// 折减到1PGA所采用的折减系数
        /// </summary>
        /// <returns></returns>
        public override double GetReductionFactor()
        {
            //默认加速度为影响系数的440倍(cm)
            var pga = this.ModelAfaMax * 440;
            //根据小震PGA决定加速度
            if (this.ModelAfaMax == 0.04) pga = 18;
            else if (this.ModelAfaMax == 0.08) pga = 35;
            else if (this.ModelAfaMax == 0.12) pga = 55;
            else if (this.ModelAfaMax == 0.16) pga = 70;
            else if (this.ModelAfaMax == 0.24) pga = 110;
            else if (this.ModelAfaMax == 0.32) pga = 140;
            //中震
            else if (this.ModelAfaMax == 0.12) pga = 50;
            else if (this.ModelAfaMax == 0.23) pga = 100;
            else if (this.ModelAfaMax == 0.34) pga = 150;
            else if (this.ModelAfaMax == 0.45) pga = 200;
            else if (this.ModelAfaMax == 0.68) pga = 300;
            else if (this.ModelAfaMax == 0.90) pga = 400;
            //大震
            else if (this.ModelAfaMax == 0.28) pga = 125;
            else if (this.ModelAfaMax == 0.5) pga = 220;
            else if (this.ModelAfaMax == 0.72) pga = 310;
            else if (this.ModelAfaMax == 0.9) pga = 400;
            else if (this.ModelAfaMax == 1.2) pga = 510;
            else if (this.ModelAfaMax == 1.4) pga = 620;
            //极罕遇地震
            else if (this.ModelAfaMax == 0.36) pga = 160;
            else if (this.ModelAfaMax == 0.72) pga = 320;
            else if (this.ModelAfaMax == 1.00) pga = 460;
            else if (this.ModelAfaMax == 1.35) pga = 600;
            else if (this.ModelAfaMax == 2.00) pga = 840;
            else if (this.ModelAfaMax == 2.43) pga = 1080;


            //小震 允许浮动
            else if(0.035 <= this.ModelAfaMax && this.ModelAfaMax <= 0.045) pga = 18;
            else if (0.07 <= this.ModelAfaMax && this.ModelAfaMax <= 0.09) pga = 35;
            else if (0.10 <= this.ModelAfaMax && this.ModelAfaMax <= 0.14) pga = 55;
            else if (0.145 <= this.ModelAfaMax && this.ModelAfaMax <= 0.175) pga = 70;
            else if (0.215 <= this.ModelAfaMax && this.ModelAfaMax <= 0.265) pga = 110;
            else if (0.285 <= this.ModelAfaMax && this.ModelAfaMax <= 0.335) pga = 140;

            //中震浮动
            else if (0.335 <= this.ModelAfaMax && this.ModelAfaMax <= 0.357) pga = 150;
            else if (0.428 <= this.ModelAfaMax && this.ModelAfaMax <= 0.473) pga = 200;
            else if (0.646 <= this.ModelAfaMax && this.ModelAfaMax <= 0.714) pga = 300;
            else if (0.855 <= this.ModelAfaMax && this.ModelAfaMax <= 0.945) pga = 400;
           
            //确定折减系数
            return 9.8E2 / (pga * this.PGAMultiplier);
        }

        /// <summary>
        /// 根据周期计算影响系数
        /// </summary>
        /// <param name="period"></param>
        /// <returns></returns>
        public override double GetAfaByPeriod(double period)
        {
            return this.PeriodToAfa(period);
        }

        /// <summary>
        /// 空的构造函数
        /// </summary>
        public GBCodeSpectrum() : base()
        {
            this.is6SameAs5Tg = false;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public GBCodeSpectrum(double tg, double afaMax, double dampRatio, bool is6Horizontal,
            double periodLength, double deltaPeriod): base()
        {
            //二段衰减规律
            this.is6SameAs5Tg = false;
            //设定信息
            this.ModelAfaMax = afaMax;
            this.ModelTg = tg;
            this.DampingRatio = dampRatio;
            this.is6Horizontal = is6Horizontal;
            this.PeriodLength = (float)periodLength;
            this.DeltaPeriod = (float)deltaPeriod;
            //添加反应谱值
            for(float period = this.DeltaPeriod; period <= periodLength; period += this.DeltaPeriod)
                this.Add(period, (float)this.PeriodToAfa(period));
        }

        /// <summary>
        /// 构造函数
        /// is_6SameAs5Tg 广东省隔震设计规范
        /// </summary>
        public GBCodeSpectrum(double tg, double afaMax, double dampRatio, bool is6Horizontal,
            double periodLength, double deltaPeriod, bool is_6SameAs5Tg) : base()
        {
            //二段衰减规律
            this.is6SameAs5Tg = is_6SameAs5Tg;
            //设定信息
            this.ModelAfaMax = afaMax;
            this.ModelTg = tg;
            this.DampingRatio = dampRatio;
            this.is6Horizontal = is6Horizontal;
            this.PeriodLength = (float)periodLength;
            this.DeltaPeriod = (float)deltaPeriod;
            //添加反应谱值
            for (float period = this.DeltaPeriod; period <= periodLength; period += this.DeltaPeriod)
                this.Add(period, (float)this.PeriodToAfa(period));
        }
    }

    /// <summary>
    /// 反应谱配型
    /// </summary>
    public enum CodeSpectrumEnum
    {
        /// <summary>
        /// 国家标准
        /// </summary>
        GB2015 = 1,

        /// <summary>
        /// 广东标准
        /// </summary>
        GD2020 = 2,
    }
}
